package com.heima.article.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.heima.apis.wemedia.IWemediaClient;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.ArticleConstants;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author itlxc
 * @since 2024-07-30
 */
@Service
@Slf4j
@Transactional
public class HotArticleServiceImpl implements HotArticleService {

    @Autowired
    private ApArticleMapper apArticleMapper;

    @Autowired
    private IWemediaClient iWemediaClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void computeHotArticle() {
        // 1.查询前5天的文章数据
        Date dateParam = DateTime.now().minusDays(50).toDate();
        List<ApArticle> apArticleList = apArticleMapper.findArticleListByLast5days(dateParam);
        // 2.计算文章的分值
        List<HotArticleVo> hotArticleVoList = countScore(apArticleList);
        // 3.为每个频道缓存30条分值较高的文章
        cacheTagToRedis(hotArticleVoList);
    }

    /**
     * 为每个频道缓存30条分值较高的文章
     * @param hotArticleVoList
     */
    private void cacheTagToRedis(List<HotArticleVo> hotArticleVoList) {
        Map<Integer, List<HotArticleVo>> hotArticleVoMap = hotArticleVoList.stream()
                .collect(Collectors.groupingBy(HotArticleVo::getChannelId));
        // 1.发起远程调用自媒体文章服务
        ResponseResult responseResult = iWemediaClient.getChannels();
        if (responseResult.getCode().equals(200)) {
            String jsonStr = JSONUtil.toJsonStr(responseResult.getData());
            List<WmChannel> wmChannelList = JSONUtil.toList(jsonStr, WmChannel.class);
            // 获取每个频道的文章
            if (CollUtil.isNotEmpty(wmChannelList)) {
                wmChannelList.forEach(wmChannel -> {
                    /*List<HotArticleVo> list = hotArticleVoList.stream()
                            .filter(hotArticleVo -> ObjectUtil.equal(wmChannel.getId(), hotArticleVo.getChannelId()))
                            .collect(Collectors.toList());*/
                    // 优化性能
                    List<HotArticleVo> list = hotArticleVoMap.get(wmChannel.getId());
                    if (CollUtil.isNotEmpty(list)) {
                        // 给文章进行排序，取30条分值较高的文章存入redis  key：频道id   value：30条分值较高的文章
                        sortAndCache(list, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + wmChannel.getId());
                    }
                });
            }
        }
        // 设置推荐数据
        // 给文章进行排序，取30条分值较高的文章存入redis  key：频道id   value：30条分值较高的文章
        sortAndCache(hotArticleVoList, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
    }

    /**
     * 给文章进行排序，取30条分值较高的文章存入redis
     * @param list
     * @param key
     */
    private void sortAndCache(List<HotArticleVo> list, String key) {
        List<HotArticleVo> hotArticleVoList = list.stream()
                    .sorted(Comparator.comparingInt(HotArticleVo::getScore).reversed())
                    .limit(30).collect(Collectors.toList());
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(hotArticleVoList));
    }

    /**
     * 计算文章的分值
     * @param apArticleList
     * @return
     */
    private List<HotArticleVo> countScore(List<ApArticle> apArticleList) {
        List<HotArticleVo> hotArticleVoList = new ArrayList<>(apArticleList.size());
        if (CollUtil.isNotEmpty(apArticleList)) {
            hotArticleVoList = apArticleList.stream().map(apArticle -> {
                HotArticleVo hotArticleVo = BeanUtil.copyProperties(apArticle, HotArticleVo.class);
                hotArticleVo.setScore(computeScore(apArticle));
                return hotArticleVo;
            }).collect(Collectors.toList());
        }
        return hotArticleVoList;
    }

    /**
     * 计算文章的分值权重
     * @param apArticle
     * @return
     */
    private Integer computeScore(ApArticle apArticle) {
        Integer score = 0;
        if (ObjectUtil.isNotNull(apArticle.getLikes())) {
            score += apArticle.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        if (ObjectUtil.isNotNull(apArticle.getViews())) {
            score += apArticle.getViews();
        }
        if (ObjectUtil.isNotNull(apArticle.getComment())) {
            score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if (ObjectUtil.isNotNull(apArticle.getCollection())) {
            score += apArticle.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        return score;
    }
}
